/*
 * shingle_types.h
 *
 *  Created on: Jun 3, 2011
 *      Author: timothy
 */

#ifndef SHINGLETYPES_H
#define SHINGLETYPES_H

#include <list>
#include <omp.h>

using namespace::std;

#include "init.h"
#include "list.h"

#ifdef BULK_ALLOCATE_SHINGLES
#define SHINGLE_CHUNK BULK_ALLOCATE_SHINGLES
#endif

class ShingleContext;
class Vertex;
class Shingle;

struct SLE_t; // Shingling List Entry _t

// Class which contains the important context variables for shingle construction.
class ShingleContext
{
	public:
		// FIELDS //
		unsigned long int large_prime; // Constant
		unsigned int s; // From args
		unsigned int c; // From args
		unsigned long int *r1; // Array of size c filled with random numbers generated at construction.
		unsigned long int *r2; // Array of size c filled with random numbers generated at construction.
		unsigned long numVertices;
		double MinimumAlignment;

		Shingle** ShingleAllocs;
		int* UnusedShingles;

		unsigned int hashConstant[5];

		// CONSTRUCTORS//
		// Generates the shingle context, creating all necessary random numbers.
		ShingleContext();
		~ShingleContext();

		// METHODS //
		int Hash(char *string);
};

class Vertex
{
	private:
	public:
		// FIELDS //
		// The ID of this vertex.
		int ID;
		// All neighbors of this vertex, including itself as the 0th entry.
		NeighborList *Neighbors;

		// CONSTRUCTORS //
		// Constructs a vertex from an input line.
		//   This destroys the input string.
		Vertex(char *line);
		~Vertex();

		// METHODS //
		void InitVertex(char *line);
		int Repair(Vertex *graph);
		void WriteGEL(FILE *out);

		// Creates a shingle from this and populates its VertexNeighbors[0] with this.ID.
		Shingle *MakeShingle(int index, unsigned long hash);
		static Vertex *CreateVertex(char *line);
};

class Shingle
{
	private:
		// Fields
		Shingle *parentBlock;
		int memCount;

		NeighborList _neighborListInner;
		NeighborListEntry _firstNeighbor;
	public:
		// FIELDS //
		int isMemoryBlock;
		// The key generated by the hashtable
		unsigned long int hashkey;
		// Contains 1 if this is an L1 shingle or 2 if this is an L2 shingle
		int ShingleType;
		// The s vertices which compose the shingle.
		int vertices[5];
		// The index at which this shingle was generated.
		int nthShingle;
		// The number of neighbors the vertex has.
		unsigned int neighborCount;


		// Contains indices of all neighbors in a shingle
		NeighborList *Neighbors;

		// CONSTRUCTORS //
		Shingle(int type, unsigned long source);
		static Shingle* InitShingle(int type, unsigned long source);
		~Shingle();
		void ClearData();

		// METHODS //
		// Creates a shingle from this and populates its ShingleNeighbors[0] with this.hashkey.
		Shingle *MakeShingle(int index, unsigned long hash);
		int CompareTo(Shingle *other);
		double AlignmentTo(Shingle *other);
		int VerifyNeighbor(Vertex *other);


		static Shingle *AllocateShingle();
		static void DeallocateShingle();

		static unsigned long MakeKey(Shingle *shingle, int index);
		static unsigned long MakeKey(Vertex *vertex, int index);
		// Gets the top S elements of the list (as per nthShingle's random
		// values) and stores them in ret[]
		static void FindTopSElems(SLE_t *ret, NeighborList *neighbors, int nthShingle);
};

typedef struct SLE_t{
	SLE_t() { }

	inline void InitSLE_t(SLE_t *out, unsigned long value, int nthShingle);

	int vertex;
	unsigned long int value;

	inline int operator>(SLE_t other) { return (value > other.value); }
	inline int operator<(SLE_t other) { return (value < other.value); }
	inline int operator==(SLE_t other) { return (value == other.value); }
	inline int operator<=(SLE_t other) { return (value <= other.value); }
	inline int operator>=(SLE_t other) { return (value >= other.value); }

	inline SLE_t(int from, int val) { vertex = from, value = val; }
} ShinglingListEntry;

extern ShingleContext *g_ShingleContext;

#endif
